• Тетрис вылетает, когда первая деталь касается низа игрового экрана, что нужно исправить?

    @mezigar Автор вопроса
    Денис, спасибо за ответ. я ещё до написания вопроса дергал этот участок кода. Если заменить значение справа от отношения больше на FieldConstants.ROW_COUNT.value - 1, то игра будет вылетать на расстоянии в 1 блок от низа экрана, если поменять условие на ROW_COUNT + 1, то все равно вылетает ,так что возвращает, либо я не понял, что вы имели ввиду.
  • Тетрис вылетает, когда первая деталь касается низа игрового экрана, что нужно исправить?

    @mezigar Автор вопроса
    mezigar, CellConstants :
    package com.example.tetrisnoactivity.constants
    
    enum class CellConstants(val value: Byte) {
        EMPTY(0), EPHEMERAL(1)
    }


    FieldConstants:
    package com.example.tetrisnoactivity.constants
    
    enum class FieldConstants(val value: Int) {
        COLUMN_COUNT(10), ROW_COUNT(20);
    }


    Block :
    package com.example.tetrisnoactivity.models;
    
    import android.graphics.Color;
    import android.graphics.Point;
    
    import androidx.annotation.NonNull;
    
    import com.example.tetrisnoactivity.constants.FieldConstants;
    
    import java.util.Random;
    
    public class Block {
        private int shapeIndex;
        private int frameNumber;
        private BlockColor color;
        private Point position;
    
        private Block(int shapeIndex, BlockColor blockColor) {
            this.frameNumber = 0;
            this.shapeIndex = shapeIndex;
            this.color = blockColor;
            this.position = new Point(FieldConstants.COLUMN_COUNT.getValue()/2, 0);
        }
    
        public static Block createBlock() {
            Random random = new Random();
            int shapeIndex = random.nextInt(Shape.values().length);
            BlockColor blockColor = BlockColor.values()
                    [random.nextInt(BlockColor.values().length)];
            Block block = new Block(shapeIndex, blockColor);
            block.position.x = block.position.x - Shape.values()
                    [shapeIndex].getStartPosition();
            return  block;
        }
    
        public static int getColor(byte value) {
            for (BlockColor colour : BlockColor.values()) {
                if (value == colour.byteValue) {
                    return colour.rgbValue;
                }
            }
            return -1;
        }
    
        public final void setState(int frame, Point position) {
            this.frameNumber = frame;
            this.position = position;
        }
    
        @NonNull
        public final byte[][] getShape(int frameNumber) {
            return Shape.values()[shapeIndex].getFrame(frameNumber).as2dByteArray();
        }
    
        public Point getPosition() {
            return this.position;
        }
    
        public final int getFrameCount() {
            return Shape.values()[shapeIndex].getFrameCount();
        }
    
        public int getFrameNumber() {
            return  frameNumber;
        }
    
        public int getColor() {
            return color.rgbValue;
        }
    
        public byte getStaticValue() {
            return  color.byteValue;
        }
    
        public enum BlockColor {
            PINK(Color.rgb(255,105,180), (byte) 2),
            GREEN(Color.rgb(0,128,0), (byte) 3),
            ORANGE(Color.rgb(255,149,0), (byte) 4),
            YELLOW(Color.rgb(255,255,0), (byte) 5),
            CYAN(Color.rgb(0,255,255), (byte) 6);
            BlockColor(int rgbValue, byte value) {
                this.rgbValue = rgbValue;
                this.byteValue = value;
            }
    
            private final int rgbValue;
            private final byte byteValue;
        }
    }


    Frame :
    package com.example.tetrisnoactivity.models
    
    import com.example.tetrisnoactivity.helpers.array2dOfByte
    
    class Frame (private val width: Int){
        val data: ArrayList<ByteArray> = ArrayList()
    
        fun addRow(byteStr: String): Frame {
            val row = ByteArray(byteStr.length)
    
            for (idx in byteStr.indices) {
                row[idx] = "${byteStr[idx]}".toByte()
            }
            data.add(row)
            return this
        }
    
        fun as2dByteArray(): Array<ByteArray> {
            val bytes = array2dOfByte(data.size, width)
            return data.toArray(bytes)
        }
    }


    Shape :

    package com.example.tetrisnoactivity.models
    
    enum class Shape(val frameCount: Int, val startPosition: Int) {
        Tetromino1(1,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return Frame(2)
                    .addRow("11")
                    .addRow("11")
            }
        },
        Tetromino2(2,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return when (frameNumber) {
                    0 -> Frame(3)
                        .addRow("110")
                        .addRow("011")
                    1 -> Frame(2)
                        .addRow("01")
                        .addRow("11")
                        .addRow("10")
                    else -> throw IllegalArgumentException("$frameNumber is an invalid frame number.")
                }
            }
        },
        Tetromino3(2,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return  when (frameNumber) {
                    0 -> Frame(3)
                        .addRow("011")
                        .addRow("110")
                    1 -> Frame(2)
                        .addRow("10")
                        .addRow("11")
                        .addRow("01")
                    else -> throw IllegalArgumentException("$frameNumber is an invalid frame number.")
                }
            }
        },
        Tetromino4(2,2) {
            override fun getFrame(frameNumber: Int): Frame {
                return when (frameNumber) {
                    0 -> Frame(4).addRow("1111")
                    1 -> Frame(1)
                        .addRow("1")
                        .addRow("1")
                        .addRow("1")
                        .addRow("1")
                    else -> throw IllegalArgumentException("$frameNumber is an invalid frame number.")
    
                }
            }
        },
        Tetromino5(4,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return when(frameNumber) {
                    0 -> Frame(3)
                        .addRow("010")
                        .addRow("111")
                    1 -> Frame(2)
                        .addRow("10")
                        .addRow("11")
                        .addRow("10")
                    2 -> Frame(3)
                        .addRow("111")
                        .addRow("010")
                    3 -> Frame(2)
                        .addRow("01")
                        .addRow("11")
                        .addRow("01")
                    else -> throw  IllegalArgumentException("$frameNumber is an ivalid frame number.")
                }
            }
        },
        Tetromino6(4,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return when (frameNumber) {
                    0 -> Frame(3)
                        .addRow("100")
                        .addRow("111")
                    1 -> Frame(2)
                        .addRow("11")
                        .addRow("10")
                        .addRow("10")
                    2 -> Frame(3)
                        .addRow("111")
                        .addRow("001")
                    3 -> Frame(2)
                        .addRow("01")
                        .addRow("01")
                        .addRow("11")
                    else -> throw  IllegalArgumentException("$frameNumber is an invalid frame number.")
                }
            }
        },
        Tetromino7(4,1) {
            override fun getFrame(frameNumber: Int): Frame {
                return when (frameNumber) {
                    0 -> Frame(3)
                        .addRow("001")
                        .addRow("111")
                    1 -> Frame(2)
                        .addRow("10")
                        .addRow("10")
                        .addRow("11")
                    2 -> Frame(3)
                        .addRow("111")
                        .addRow("100")
                    3 -> Frame(2)
                        .addRow("11")
                        .addRow("01")
                        .addRow("01")
                    else -> throw IllegalArgumentException("$frameNumber is an invalid frame number.")
                }
            }
        };
        abstract fun getFrame(FrameNumber: Int): Frame
    }
  • Тетрис вылетает, когда первая деталь касается низа игрового экрана, что нужно исправить?

    @mezigar Автор вопроса
    Борис Животное, Спасибо, приму к сведению! Если ещё какой-то код требуется, то обязательно скину
  • Тетрис вылетает, когда первая деталь касается низа игрового экрана, что нужно исправить?

    @mezigar Автор вопроса
    Борис Животное код gameActivity,
    package com.example.tetrisnoactivity
    
    import android.os.Bundle
    import android.view.MotionEvent
    import android.view.View
    import android.widget.Button
    import android.widget.TextView
    import androidx.appcompat.app.AppCompatActivity
    import com.example.tetrisnoactivity.models.AppModel
    import com.example.tetrisnoactivity.storage.AppPreferences
    import com.example.tetrisnoactivity.view.TetrisView
    
    class GameActivity : AppCompatActivity() {
    
        var tvHighScore: TextView? = null
        var tvCurrentScore: TextView? = null
        var appPreferences: AppPreferences? = null
    
        private lateinit var tetrisView: TetrisView
        private val appModel: AppModel = AppModel()
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_game)
            appPreferences = AppPreferences(this)
    
            val btnRestart = findViewById<Button>(R.id.btn_restart)
            tvHighScore = findViewById<TextView>(R.id.tv_high_score)
            tvCurrentScore = findViewById<TextView>(R.id.tv_current_score)
            tetrisView = findViewById<TetrisView>(R.id.view_tetris)
            tetrisView.setActivity(this)
            tetrisView.setModel(appModel)
            tetrisView.setOnTouchListener(this::onTetrisViewTouch)
            btnRestart.setOnClickListener(this::btnRestartClick)
            updateHighScore()
            updateCurrentScore()
        }
    
        private fun btnRestartClick(view: View) {
            appModel.restartGame()
        }
    
        private fun onTetrisViewTouch(view:View, event: MotionEvent): Boolean {
            if (appModel.isGameOver() || appModel.isGameAwaitingStart()) {
                appModel.startGame()
                tetrisView.setGameCommandWithDelay(AppModel.Motions.DOWN)
            } else if (appModel.isGameActive()) {
                when (resolveTouchDirection(view, event)) {
                    0 -> moveTetromino(AppModel.Motions.LEFT)
                    1 -> moveTetromino(AppModel.Motions.ROTATE)
                    2 -> moveTetromino(AppModel.Motions.DOWN)
                    3 -> moveTetromino(AppModel.Motions.RIGHT)
                }
            }
            return true
        }
    
        private fun resolveTouchDirection(view: View, event: MotionEvent): Int {
            val x = event.x / view.width
            val y = event.y / view.height
            val direction: Int
            direction = if (y > x) {
                if (x > 1 -y) 2 else 0
            } else {
                if (x > 1 - y) 3 else 1
            }
            return direction
        }
    
        private fun moveTetromino(motion: AppModel.Motions) {
            if (appModel.isGameActive()) {
                tetrisView.setGameCommand(motion)
            }
        }
    
        private fun updateHighScore() {
            tvHighScore?.text = "${appPreferences?.getHighScore()}"
        }
    
        private fun updateCurrentScore() {
            tvCurrentScore?.text = "0"
        }
    }


    Cod AppPreferences :
    package com.example.tetrisnoactivity.storage
    
    import android.content.Context
    import android.content.SharedPreferences
    
    class AppPreferences(ctx: Context) {
        var data: SharedPreferences = ctx.getSharedPreferences(
            "APP_PREFERENCES", Context.MODE_PRIVATE
        )
    
        fun saveHighScore(highScore: Int) {
            data.edit().putInt("HIGH_SCORE", highScore).apply()
        }
    
        fun getHighScore(): Int{
            return data.getInt("HIGH_SCORE", 0)
        }
    
        fun clearHighScore() {
            data.edit().putInt("HIGH_SCORE", 0).apply()
        }
    
    }
    
    код TetrisView:
    
    <code>
    package com.example.tetrisnoactivity.view
    
    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Color
    import android.graphics.Paint
    import android.graphics.RectF
    import android.os.Handler
    import android.os.Message
    import android.util.AttributeSet
    import android.view.View
    import android.widget.Toast
    //import androidx.annotation.Dimension
    import com.example.tetrisnoactivity.GameActivity
    import com.example.tetrisnoactivity.constants.CellConstants
    import com.example.tetrisnoactivity.constants.FieldConstants
    import com.example.tetrisnoactivity.models.AppModel
    import com.example.tetrisnoactivity.models.Block
    
    class TetrisView : View {
        private val paint = Paint()
        private var lastMove: Long = 0
        private var model: AppModel? = null
        private var activity: GameActivity? = null
        private val viewHandler = ViewHandler(this)
        private var cellSize: Dimension = Dimension(0,0)
        private var frameOffset: Dimension = Dimension(0,0)
    
        constructor(context: Context, attrs: AttributeSet): super(context, attrs)
    
        constructor(context: Context, attrs: AttributeSet, defStyle: Int): super(context, attrs, defStyle)
    
        companion object {
            private val DELAY = 500
            private val BLOCK_OFFSET = 2
            private val FRAME_OFFSET_BASE = 10
        }
    
        private class ViewHandler(private val owner: TetrisView): Handler() {
            override fun handleMessage(msg: Message) {
                if (msg.what == 0) {
                    if (owner.model != null) {
                        if (owner.model!!.isGameOver()) {
                            owner.model?.endGame()
                            Toast.makeText(owner.activity, "Game Over", Toast.LENGTH_LONG).show();
                        }
                        if (owner.model!!.isGameActive()) {
                            owner.setGameCommandWithDelay(AppModel.Motions.DOWN)
                        }
                    }
                }
            }
            fun sleep(delay: Long) {
                this.removeMessages(0)
                sendMessageDelayed(obtainMessage(0), delay)
            }
        }
    
        private data class Dimension(val width: Int, val height: Int)
    
        fun setModel(model: AppModel) {
            this.model = model
        }
    
        fun setActivity(gameActivity: GameActivity) {
            this.activity = gameActivity
        }
    
        fun setGameCommand(move: AppModel.Motions) {
            if ((model != null)  && (model?.currentState == AppModel.Statuses.ACTIVE.name)) {
                if (AppModel.Motions.DOWN == move) {
                    model?.generateField(move.name)
                    invalidate()
                    return
                }
                setGameCommandWithDelay(move)
            }
        }
    
        fun setGameCommandWithDelay(move: AppModel.Motions) {
            val now = System.currentTimeMillis()
            if (now - lastMove > DELAY) {
                model?.generateField(move.name)
                invalidate()
                lastMove = now
            }
            updateScores()
            viewHandler.sleep(DELAY.toLong())
        }
    
        private fun updateScores() {
            activity?.tvCurrentScore?.text = "${model?.score}"
            activity?.tvHighScore?.text = "${activity?.appPreferences?.getHighScore()}"
        }
    
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            drawFrame(canvas)
            if (model != null) {
                for (i in 0 until FieldConstants.ROW_COUNT.value) {
                    for(j in 0 until FieldConstants.COLUMN_COUNT.value) {
                        drawCell(canvas, i, j)
                    }
                }
            }
        }
    
        private fun drawFrame(canvas: Canvas) {
            paint.color = Color.LTGRAY
            canvas.drawRect(frameOffset.width.toFloat(),
            frameOffset.height.toFloat(),
                width - frameOffset.width.toFloat(),
            height - frameOffset.height.toFloat(),
            paint)
        }
    
        private fun drawCell(canvas: Canvas, row: Int, col: Int) {
            val cellStatus = model?.getCellStatus(row,col)
            if (CellConstants.EMPTY.value != cellStatus) {
                val color = if (CellConstants.EPHEMERAL.value == cellStatus) {
                    model?.currentBlock?.color
                } else {
                    Block.getColor(cellStatus as Byte)
                }
                drawCell(canvas,col,row, color as Int)
            }
        }
    
        private fun drawCell(canvas: Canvas,x: Int, y: Int, rgbColor: Int) {
            paint.color = rgbColor
            val top: Float = (frameOffset.height + y * cellSize.height + BLOCK_OFFSET).toFloat()
            val left: Float = (frameOffset.width + x * cellSize.width + BLOCK_OFFSET).toFloat()
            val bottom: Float = (frameOffset.height + (y + 1) * cellSize.height - BLOCK_OFFSET).toFloat()
            val right: Float = (frameOffset.width + (x + 1) * cellSize.width - BLOCK_OFFSET).toFloat()
    
            val rectangle = RectF(left, top, right, bottom)
            canvas.drawRoundRect(rectangle, 4F, 4F, paint)
    
        }
    
        override fun onSizeChanged(width: Int, height: Int, previousWidth: Int, previousHeight: Int) {
            super.onSizeChanged(width, height, previousWidth, previousHeight)
            val cellWidth = (width - 2 * FRAME_OFFSET_BASE) / FieldConstants.COLUMN_COUNT.value
            val cellHeight = (height - 2 * FRAME_OFFSET_BASE) / FieldConstants.ROW_COUNT.value
    
            val n = Math.min(cellWidth, cellHeight)
            this.cellSize = Dimension(n, n)
            val offsetX = (width - FieldConstants.COLUMN_COUNT.value * n) / 2
            val offsetY = (height - FieldConstants.ROW_COUNT.value * n) / 2
            this.frameOffset = Dimension(offsetX, offsetY)
        }
    }
    </code>
  • Почему при запуске .py через консоль файл не выполняется?

    @mezigar Автор вопроса
    Егор, Я заметил вашу заметку, но ничего не изменилось
  • Почему при запуске .py через консоль файл не выполняется?

    @mezigar Автор вопроса
    я нахожусь в папке с файлом, но всё равно не работает
  • Как узнать, что ячейка является объединенной?

    @mezigar Автор вопроса
    Akina, Спасибо за быстрый отклик, но нет, не требуется. Ещё раз спасибо!