#chess

1 messages · Page 1 of 1 (latest)

still apex
#

(making a thread because we've gone on for a while)

somber canyon
#

good idea

still apex
#

So, every piece can move, right

#

therefore, every piece should be able to tell you a list of squares it's allowed to move to

somber canyon
#

right, which was the intention of this function

still apex
#

you don't care if it's a Rook or a Pawn

#

you just want to know where the piece can move

somber canyon
#

obviously ive only done rook movement logic so far

still apex
#

as-is, you'll wind up having to do something like this

#
if (piece is Rook)
  (piece as Rook).GetMoves();
else if (piece is Pawn)
  (piece as Pawn).GetMoves();
#

etc.

#

so, here's what you should do:

#
public abstract class Piece { 
    public Vector2Int position; //Position On Board XY 1-8
    public Type type; // Piece Type EG: Rook, King ETC
    public Colour colour; // White/Black

    protected Board board;
    public void SetBoard(Board board) { this.board = board; }

    public abstract List<Vector2Int> LegalMoves();
}
#

that last method is abstract

#

therefore, anything that inherits from Piece must provide a definition for it

#

e.g.

#
public class Rook {
    public override List<Vector2Int> LegalMoves() {
        return new List<Vector2Int>();
    }
}
#

obviously that's not a correct implementation

#

but you'd write something appropriate there

#

now, I can do this:

Piece piece = /* idk */
foreach (var move in piece.LegalMoves()) {
   // do something to highlight the square
}
#

no matter what the piece is, we can just ask it for where it can move

#

we could go a step further, too -- consider how it's always illegal to move in a way that checks your king

somber canyon
#

Right, so the public abstract List<Vector2Int> LegalMoves(); would that constantly update if legal moves change

still apex
#

so every piece should check for this when considering if a move is legal

#

so, I would actually just make a virtual method that decides if a single move is legal

#
public virtual bool LegalMove(Vector2Int pos) { 
  /* code here */
}
somber canyon
#

so a seperate method for the move itself that the person is attempting to do, right

still apex
#

a virtual method is one that can be overridden by a child class

#

but the child can still call it

#

so, Piece's LegalMove method would check if the player's king is now in check after making that move

#

then, in Rook, you'd do something like

somber canyon
#

Right I'm following, is it alright first if i sort out the original piece situation real quick?

still apex
#
public override void LegalMove(Vector2Int pos) {
  if (!base.LegalMove(pos))
     return false;
  // check if you can move there
}
#

oh yeah, go ahead

#

checking legal moves is actually gonna be a little tricky

#

e.g. what if I capture a piece that would otherwise be threatening my king if I just moved out of the way?

#

you'd want a way to make a copy of the board state, make the move, and then check if the king is in danger

#

things can get tricky quickly :p

somber canyon
#

Yeah, I think i can do it though. The language i know best is JavaScript and as im sure you can tell im a beginner at C# so a lot of these new things in it take a bit to wrap my head around

still apex
#

I'd have to sit down and think about that for a little while

#

Of course, you could always start with just "where can this piece go?", even if it would be an illegal board state

#

and then, later on, add that logic to Piece's LegalMove function

somber canyon
#

Yeah that's probably best.

#

So the rook script

#

does the class need to derive from piece still? because it also needs to from MonoBehaviour to attatch to a prefab

still apex
#

Right. You'd make Piece a MonoBehaviour

#

I am second-guessing myself on that, though

somber canyon
#

but i also need to attach the rook script

still apex
#

this will make it harder to make a copy of the current board state so that you can check if a move is legal

somber canyon
#

Yeah true

still apex
#

it's a Piece, which is a MonoBehaviour

somber canyon
#

it says this weirdly though. public class Rook : Piece even though i have this

#

cs public abstract class Piece : MonoBehaviour and piece is here

still apex
#

make sure it refreshed the files and doesn't have any compile errors

still apex
# still apex specifically for this reason

so there's another way you can think about this whole thing:

  • the board state is just made of plain old C# classes
  • you transform that into physical pieces on the board whenever you want to update the visuals
#

so the pieces on the board are just a snapshot of what the board state is

somber canyon
#

hmm. That could be a possibility. So i'd only be touching the board layout and then just listening for changes to update the board visually

#

Maybe it'd be easier

still apex
#

Yeah.

somber canyon
#

hey i could just rewrite this whole thing and copy stuff over

#

it might be easier

still apex
#

I'd need to think about it some more :p

#

I definitely think that you should have an abstract Piece class that each specific kind of piece inherits from

#

but then the board would just be a bunch of dumb objects

#

when you select one, it asks the corresponding piece where it can move

somber canyon
#

not sure

still apex
#

yeah, it feels better for a game where you need to look at future board states

#

(especially if you try making an AI for it :p )

#

I haven't implemented a board game before, so it makes sense I wouldn't think of that at first

somber canyon
#

yeah i did think one day of trying some machine learning against myself and seeing if i can train an ai from scratch to beat me lol. I mean i'll likely make it multiplayer first

still apex
#

and, of course, another thing: the simplest way to store the board state would be...an array of structs storing color and piece type

#

in that case, you wouldn't have a list of Rooks and Pawns and Bishops

#

it'd just be dumb data

#

and you'd have a function that knows what to do for every piece type

#

...which would completely get rid of the abstract Piece class

still apex
#

you wouldn't be able to just say pieces[new(3,4)].GetLegalMoves()

somber canyon
#

you mean that i would be able?

still apex
#

man, I might be less confident about what to do than when I started talking about this, haha

#

Game Design (tm)

somber canyon
#

lol

#

I think i'm going to start again with a new project

#

and port code over

#

It'll probably be easier

still apex
#

I'd definitely look up some tutorials. Even if you don't follow them, you can see how they think that data should be structured

#

there are several different ways to do this and I can see headaches with each one

somber canyon
#

Yeah that's what I did initially, but they tended to trail down a path which wasn't very expandable for implementations like multiplayer and such

#

I've been occasionally referring to some just to see what they do for certain functionality

still apex
#
  1. the object-oriented programming way
#

each piece is a class, and each class has a function that tells you where that piece can legally move

#
  1. the procedural way
#

each piece is a bit of data, and there's a function that can tell you where that piece can move

#

"OOP" is just when you glue the functions onto the data

#

it's really nice for modeling many kinds of problems

#

you don't have a list of pieces and a big function that knows how to handle all of the pieces

#

each piece just knows what it can do

somber canyon
#

Both have their benefits and drawbacks so I honestly can't decide. I'm leaning towards the new method as the board as a whole would just be easier to see and make the more complicated logic behind legal moves to do with checking the king and such easier

still apex
#

also, one benefit of having the pieces on the board separate from the actual logic

#

you can change how the game is visualized very easily

somber canyon
#

Which would probably make netcode easier

still apex
#

right

#

you'd just synchronize the board state

#

no need to like

#

network the transforms of every single piece

somber canyon
#

Maybe this is the way to go then.

still apex
#

yeah, 100% if you want to make this networked later

#

in that case, you want to have a nice, small, tidy state

#

and derive as much as you can from that state

somber canyon
#

Right, I've already looked at some courses on multiplayer using unity's fairly new system and it does look like a hassle, so best to make it as easy as possible

somber canyon
#

I genuinely have no idea what's going on here

using System;
using UnityEngine;

[CreateAssetMenu(fileName = "New Board Layout", menuName = "ScriptableObjects/Board Layout")]
public class BoardLayout : ScriptableObject
{

    public Piece[] pieces;
    public const int boardSize = 8;

nothing at all here, ive refreshed unity and even restarted

still apex
#

Piece probably isn't serializable

somber canyon
#

im stupid, I forgot that was a thing, thank you. I was only looking at the script itself not thinking about whether the class itself was

somber canyon
#
public enum Type
{
    King,
    Queen,
    Rook,
    Bishop,
    Knight,
    Pawn
}

public enum PieceColour
{
    White,
    Black
}

[Serializable]
public abstract class Piece : MonoBehaviour
{
    public PieceColour colour;
    public Type type;
    public Vector2Int position;

    public abstract List<Vector2Int> LegalMoves();

}











using System.Collections.Generic;
using UnityEngine;

public class Rook : Piece
{
    public Vector2Int[] moveDirections = new Vector2Int[]
    {Vector2Int.left, Vector2Int.up, Vector2Int.right, Vector2Int.down };

    public override List<Vector2Int> LegalMoves()
    {

        List<Vector2Int> legalMoves = new List<Vector2Int>();

        foreach (Vector2Int direction in moveDirections)
        {
            for (int i = 1; i <= BoardLayout.boardSize; i++)
            {
                Vector2Int coord = ?
            }
        }

        return legalMoves;
        
    }

}```

So following what you said i have this again, but i think im still a bit unclear on how these overrides work so im not sure as to how i would pass the piece's position into this function
still apex
#

If you go with this design -- where there's a Piece class that holds information about the piece -- then you can just access position!

#

you don't have to pass the position in; the Piece knows its own position

somber canyon
#

how do i go about accessing it though? Piece.position won't work as i expect because it isnt static

#

is there anything im doing wrong with the override function

still apex
#

just, position

#

or this.position, if you want to be more explicit

somber canyon
#

ah, that makes sense

somber canyon
still apex
#

if we go with the "pieces are just visuals" design (which I do think is the right way to go, after talking through it), then Piece wouldn't be a behaviour

somber canyon
#

Will the rook script still be then?

still apex
#

I would expect that Rook/Bishop/Pawn/etc. would be derivatives of Piece

#

so they would also not be behaviours

somber canyon
#

Gotcha

somber canyon
#

So, i've done the basic scripting for calculating legal moves of all pieces (ignoring checks for now). But im not sure as to how im supposed to fill the scriptable object with pieces if it piece doesnt inherit from monobehaviour, should i create a seperate struct just with piece prefabs, type, spawn position etc?

still apex
#

I'd make a list of structs that store the type, position, and color

#

you'd look up the prefab based on the type, like you were doing originally

somber canyon
#

Yeah that's what i was thinking, ty

somber canyon
# still apex you'd look up the prefab based on the type, like you were doing originally

does that not mean im still going to end up with what i had before tho? because then im going to have this PieceLayout struct in addition to the piece struct on the scripts of the pieces

[Serializable]
public abstract class Piece
{
    public PieceColour colour;
    public Type type;
    public Vector2Int position;

    protected BoardLayout boardLayout;

    public void SetBoard(BoardLayout board)
    {
        boardLayout = board;
    }

    public abstract List<Vector2Int> LegalMoves();

}

[Serializable]
public struct PieceLayout
{
    public PieceColour colour;
    public Type type;
    public Vector2Int position;

}```
still apex
#

You will, yeah -- and I guess you could re-use the Piece class if you really wanted to.

One thing you wouldn't want to do is directly use the list of pieces from the BoardLayout without making a copy of them first. You'd be directly manipulating the ScriptableObject's contents, so you'd wind up changing the asset on disk!

somber canyon
#

So i need a separate one for only start layout and a new one entirely for the current layout

still apex
#

Right, since those are two separate concepts here (the Piece has some extra information, like a reference to the Board)

#

if you moved all of that out of the piece (maybe the Board itself decides where pieces can move), then I bet you could make the start config use the exact same type

somber canyon
#

Alright, ill give it a go

somber canyon
#

Any idea why this has turned into this?

#
public class Piece : MonoBehaviour
{
    public PieceColour colour;
    public Type type;
    public Vector2Int position;

    protected BoardLayout boardLayout;

    public void SetBoard(BoardLayout board)
    {
        boardLayout = board;
    }

}```
#
[SerializeField] private BoardLayout initialLayout; // Do not modify | Will permanently write to disk!```
#

also im not sure if this is the right way to do this because i've never used these before, but ive added this interface

#
public interface IDefinePiece
{
    public abstract void DefinePieceValues(Piece piece);
}```
#

and then referenced it in each script

#
        IDefinePiece script = instantiatedObject.GetComponent<IDefinePiece>();

        script.DefinePieceValues(piece);``` in order to give each piece its properties here
still apex
#

if Piece is a monobehaviour, then it'll expect you to assign references to those fields

somber canyon
#

ah i've got this damn issue again

#

now i cant put the scripts on the prefabs

#

ahhhh

#

god ive got myself in a loop

#

I dont know how to get out of

still apex
#

you need to decide if Piece is going to be a monobehaviour attached to things in the scene

#

or just data

#

I think your original plan was the latter

somber canyon
#

Yeah, but im not sure how to use that data if its not attatched to the pieces in play

still apex
#

I would have the Piece class refer to a specific object in the scene

#

maybe you can call that component PhysicalPiece

#

or something

somber canyon
#

As in like add a game object reference?

still apex
#

Yeah.

#

Or a reference to PhysicalPiece or something

somber canyon
#

Should I make piece a scriptable object in that case

still apex
#

I'm not sure there! I've only ever used SOs for readonly data

somber canyon
#

Doesn’t a script have to be attached to an object to run if not though?

#

And obviously I can’t do that because it doesn’t inherit monobehaviour

still apex
#

well, it's not like pieces need to do something every frame, right

#

you'd just run functions on the Piece objects as needed

somber canyon
#

So I’d just have all the scripts attached to my game controller and run functions on them as needed then?